home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
IRIS Performer 2.2 Friends Demo
/
SGI IRIS Performer 2.2 Friends Demo.iso
/
friends
/
medit
/
pfLoader
/
Internalstuff
/
filer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-11-20
|
30KB
|
1,230 lines
/************************************************************************
Data creation/manipulation routines for the filer
************************************************************************/
/************************************************************************
Alias some data types to ease transition from ModelWorks to libmw
************************************************************************/
#ifdef POX
#define MaxName mwMaxName
#define FileError mwFileError
#define FileErrorType mwErrorType
#define FileHadNormals mwFileHadNormals
#define FreeTree mwFreeTree
#define NewTreeBranch mwNewTreeBranch
#define ScanTree mwScanTree
#define AddPolygon mwAddPolygon
#define FreePolygon mwFreePolygon
#define CopyOfPolygon mwCopyOfPolygon
#define CopyOfPolygonBead mwCopyOfPolygonBead
#ifndef TX_NULL
#define TX_NULL 0
#endif
typedef mwFile ModelFile;
typedef mwFilePtr ModelFilePtr;
typedef mwMaterial Material;
typedef mwMaterialPtr MaterialPtr;
typedef mwTexture Texture;
typedef mwTexturePtr TexturePtr;
typedef mwObject ModelObject;
typedef mwObjectPtr ModelObjectPtr;
typedef mwTree Tree;
typedef mwTreePtr TreePtr;
typedef mwPolygon Polygon;
typedef mwPolygonPtr PolygonPtr;
typedef mwPolygonBead PolygonBead;
typedef mwPolygonBeadPtr PolygonBeadPtr;
/* Hierarchy branches */
#define GroupBranch mwGroupBranch
#define PolygonBranch mwPolygonBranch
#define LodBranch mwLodBranch
#define InstanceBranch mwInstanceBranch
#define SwitchBranch mwSwitchBranch
#define DcsBranch mwDcsBranch
#define VRMLBranch mwVRMLBranch
#define SolidBranch mwSolidBranch
/* Engine branches */
#define ActivatorEngine mwActivatorEngine
#define DeactivatorEngine mwDeactivatorEngine
#define TimeEngine mwTimeEngine
#define LineEngine mwLineEngine
#define AngleEngine mwAngleEngine
#define WaveEngine mwWaveEngine
#define SensorEngine mwSensorEngine
#define ScalarEngine mwScalarEngine
#define SplineEngine mwSplineEngine
#define CompareEngine mwCompareEngine
#define MatrixEngine mwMatrixEngine
#define SwitchOutput mwSwitchOutput
#define DcsOutput mwDcsOutput
#else
#define MaxName meditMaxName
#define FileError meditFileError
#define FileErrorType meditErrorType
#define FileHadNormals meditFileHadNormals
#ifndef TX_NULL
#define TX_NULL 0
#endif
#define mwFreeFile meditFreeFile
#define mwOriginalPath meditOriginalPath
#define FileHadNormals meditFileHadNormals
#define mwSeqCycle meditSeqCycle
#define mwSeqCycle meditSeqCycle
#define ReadModel ReadMedit
#define WriteModel WriteMedit
#define CurrentModelFile CurrentMeditFile
#define mwErrorList meditErrorList
#define NewModelFile NewMeditFile
#define AddObject meditAddObject
#define NewTreeBranch meditNewTreeBranch
#define mwAddTreeBranch meditAddTreeBranch
#define mwAddMaterial meditAddMaterial
#define mwAddTexture meditAddTexture
#define AddPolygon meditAddPolygon
#define mwAddPolygonBead meditAddPolygonBead
#define mwConvertTo_Y_is_up meditConvertTo_Y_is_up
#define mwConvertTo_Z_is_up meditConvertTo_Z_is_up
typedef meditFile ModelFile;
typedef meditFilePtr ModelFilePtr;
typedef meditMaterial Material;
typedef meditMaterialPtr MaterialPtr;
typedef meditTexture Texture;
typedef meditTexturePtr TexturePtr;
typedef meditObject ModelObject;
typedef meditObjectPtr ModelObjectPtr;
typedef meditTree Tree;
typedef meditTreePtr TreePtr;
typedef meditPolygon Polygon;
typedef meditPolygonPtr PolygonPtr;
typedef meditPolygonBead PolygonBead;
typedef meditPolygonBeadPtr PolygonBeadPtr;
/* Hierarchy branches */
#define GroupBranch meditGroupBranch
#define PolygonBranch meditPolygonBranch
#define LodBranch meditLodBranch
#define InstanceBranch meditInstanceBranch
#define SwitchBranch meditSwitchBranch
#define DcsBranch meditDcsBranch
#define VRMLBranch meditVRMLBranch
#define SolidBranch meditSolidBranch
/* Engine branches */
#define ActivatorEngine meditActivatorEngine
#define DeactivatorEngine meditDeactivatorEngine
#define TimeEngine meditTimeEngine
#define LineEngine meditLineEngine
#define AngleEngine meditAngleEngine
#define WaveEngine meditWaveEngine
#define SensorEngine meditSensorEngine
#define ScalarEngine meditScalarEngine
#define SplineEngine meditSplineEngine
#define CompareEngine meditCompareEngine
#define MatrixEngine meditMatrixEngine
#define SwitchOutput meditSwitchOutput
#define DcsOutput meditDcsOutput
#endif
/************************************************************************
Memory management
************************************************************************/
#define Free free
#define Allocate malloc
#define Reallocate realloc
#define CopyOfString strdup
/************************************************************************
Some defines to make coding nicer
************************************************************************/
#define LoopThroughAllObjects(o) for (o=CurrentModelFile->FirstObject; o; o=o->Next)
#define LoopThroughAllTextures(t) for (t=CurrentModelFile->FirstTexture; t; t=t->Next)
#define LoopThroughAllMaterials(m) for (m=CurrentModelFile->FirstMaterial; m; m=m->Next)
#define LoopThroughBranchesPolygons(t, p) for (p=t->FirstPolygon; p; p=p->Next)
#define LoopThroughPolygonsBeads(p, pb) for (pb=p->FirstBead; pb; pb=pb->Next)
/************************************************************************
Global variables
************************************************************************/
flag FileHadNormals;
ModelFilePtr CurrentModelFile;
char mwOriginalPath[MaxFileName];
static flag ReadingExternal;
static ModelObjectPtr ExternalObject;
static flag MissingTextures;
static flag CurrentSmoothing;
static char ProgName[] = "ModelWorks";
static char FileExtension[] = ".medit";
static char FilePath[MaxFileName], FileName[MaxFileName];
static flag OnlySaveUsed = FALSE;
static ModelObjectPtr ObjectBeingSaved = NULL;
static void FreeExternalFile(reg ModelFilePtr f);
static MaterialPtr *CurrentMaterial(void)
{
static MaterialPtr CurrentMat = NULL;
return &CurrentMat;
}
static MaterialPtr *FirstMaterial(void)
{
return &(CurrentModelFile->FirstMaterial);
}
#define DefaultColour 0xff808080
/************************************************************************
Errors
************************************************************************/
flag FileError;
int FileErrorType;
#define ifbad(x) if (!(x))
#define GetStuff(x) ifbad(x) return
enum {
REACHED_END=0, /* Types of error */
UNKNOWN_FILE,
BAD_FILE,
FILE_NOT_FOUND,
TOO_MANY_REALS,
BAD_STRING,
BAD_REVISION,
BAD_MATERIAL_INDEX,
BAD_MATERIAL,
BAD_VERTEX,
BAD_VERTEX_INDEX,
BAD_POLYGON,
BAD_LIGHTING,
BAD_MATERIAL_IN_POLY,
NOT_ENOUGH_VERTICES,
BAD_SUB_OBJECT,
SUB_OBJECT_NOT_FOUND,
BAD_LOD,
BAD_TREE,
BAD_OBJECT,
BAD_TEXTURE,
BAD_VIEW
};
char *mwErrorList[] = {
"Unexpected end of file",
"Not a model file",
"Bad file",
"File not found",
"Tried to read/write too many reals",
"Bad string in file",
"Unsupported file revision. You need a newer version of the modeller or file exporter...",
"Bad material index",
"Error in materials",
"Bad vertex definition",
"Bad vertex index",
"Bad polygon definition",
"Unknown lighting in polygon",
"Polygon has bad material",
"Polygon has less than 3 vertices",
"Rubbish in sub object",
"Undefined sub object in Lod",
"Rubbish in LOD definition",
"Bad tree definition",
"Bad object definition",
"Bad texture definition",
"Bad view definition"
};
static void SetError(int type)
{
FileError = TRUE;
FileErrorType = type;
}
static void fail(char *function, char *message)
{
fprintf(stderr, "%s:\n%s\n", function, message);
exit(666);
}
/************************************************************************
Decide the byte sex of the machine
************************************************************************/
static boolean BigEndian(void)
{
int x = 1;
char *c = (char*)&x;
return (*c ISNT 1);
}
/************************************************************************
See if a file is an image file
************************************************************************/
#define IMAGIC 0732
static boolean IsAnImageFile(char *name)
{
reg FILE *f;
reg byte h0 = 0, h1 = 0;
if (f = fopen(name,"rb")) {
h0 = fgetc(f);
h1 = fgetc(f);
fclose(f);
return ( (((h0<<8)|h1) IS IMAGIC) OR (((h1<<8)|h0) IS IMAGIC) );
}
else {
return FALSE;
}
}
/************************************************************************
Split a filename into path/name
************************************************************************/
static void SplitFileName(reg char *s, reg char **path, reg char **name)
{
char *search, *find;
static char workspace[MaxFileName], nullpath[] = "\0";
search = workspace;
strcpy(workspace,s);
while (find = strchr(search,'/')) {
search = ++find;
}
if (search IS workspace) { /* No path in name... */
*path = nullpath;
*name = search;
}
else {
*path = workspace;
*name = search--;
*search = '\0'; /* Split into path/name... */
}
}
/************************************************************************
Search for a file....
************************************************************************/
static boolean CheckFile(reg char *file, reg boolean (*check)(char*))
{
reg int type;
struct stat statinfo;
if (stat(file, &statinfo) ISNT -1) {
type = statinfo.st_mode & S_IFMT;
if (type IS S_IFREG) {
if (check) {
return check(file);
}
else {
return TRUE;
}
}
}
return FALSE;
}
static char *SearchForFile(reg char *searchpath, reg boolean (*check)(char*), reg char *name)
{
reg flag found;
struct stat statinfo;
reg int i, nofiles, type;
char recurse[MaxFileName];
struct dirent **filelist, *this;
static char result[MaxFileName];
nofiles = scandir(searchpath, &filelist, NULL, NULL);
if (nofiles > 0) {
/* Search the directory */
found = FALSE;
for (i=0; i<nofiles; i++) {
this = filelist[i];
this->d_ino = FALSE;
if (this->d_name[0] ISNT '.') { /* Ignore system files */
sprintf(result, "%s/%s", searchpath, this->d_name);
if (!strcmp(this->d_name, name)) {
if (CheckFile(result, check)) {
found = TRUE;
break;
}
}
else if (stat(result, &statinfo) ISNT -1) {
type = statinfo.st_mode & S_IFMT;
this->d_ino = (type IS S_IFDIR); /* flag the directories... */
}
}
}
/* If (!found), search any subdirectorys */
if (!found) {
for (i=0; i<nofiles; i++) {
this = filelist[i];
if (this->d_ino) {
sprintf(recurse, "%s/%s", searchpath, this->d_name);
if (SearchForFile(recurse, check, name)) {
found = TRUE;
break;
}
}
}
}
/* Free up storage created by scandir */
for (i=0; i<nofiles; i++) {
free(filelist[i]);
}
free(filelist);
/* Return file name if found */
if (found) {
return result;
}
}
return NULL;
}
static char *FindFile(reg char *startname, reg boolean (*check)(char*), reg char *startpath, reg char *subdirectory)
{
reg char *nn;
reg flag done;
static char filename[MaxFileName];
char *path, *name, searchpath[MaxFileName];
/* Try relative filename. This is first because this is how we tell you to organise things... */
done = FALSE;
nn = startname;
while (!strncmp(nn, "./", 2)) {
nn += 2;
done = TRUE;
}
if (done) {
sprintf(filename, "%s/%s", startpath, nn);
if (CheckFile(filename, check)) {
return filename;
}
}
/* Try the absolute filename */
if (startname[0] IS '/') {
strcpy(filename, startname);
if (CheckFile(filename, check)) {
return filename;
}
}
/* Look in the directory where the model file is */
SplitFileName(startname, &path, &name);
sprintf(filename, "%s/%s", startpath, name);
if (CheckFile(filename, check)) {
return filename;
}
/* Look in the directory where it was last saved */
SplitFileName(startname, &path, &name);
sprintf(filename, "%s/%s", mwOriginalPath, name);
if (CheckFile(filename, check)) {
return filename;
}
/* Search the directory tree below the model file */
sprintf(searchpath, "%s/%s", startpath, subdirectory);
return SearchForFile(searchpath, check, name);
}
/************************************************************************
Start creating a new model file
************************************************************************/
ModelFilePtr NewModelFile(void)
{
reg ModelFilePtr f;
CurrentModelFile = f = Allocate(sizeof(ModelFile));
f->FirstObject = NULL;
f->FirstTexture = NULL;
f->FirstMaterial = NULL;
return f;
}
/************************************************************************
Storage routines - materials/textures
************************************************************************/
static MaterialPtr NewMaterial(void)
{
reg int i;
reg MaterialPtr new = Allocate(sizeof(Material));
new->Next = NULL;
new->Name = NULL;
new->Used = FALSE;
new->Name = CopyOfString("Unnamed");
for (i=0; i<3; i++) { /* A grey material */
new->Ambient[i] = 0.2;
new->Diffuse[i] = 0.5;
new->Specular[i] = 1.0;
new->Emissive[i] = 0.0;
}
new->Shine = 64;
new->Alpha = 1.0;
new->pfdef = NULL;
return new;
}
static void FreeMaterial(MaterialPtr m)
{
if (m) {
if (m->Name) {
Free(m->Name);
}
Free(m);
}
}
static void AddMaterial(MaterialPtr m)
{
reg MaterialPtr search;
if (search = CurrentModelFile->FirstMaterial) {
while (search->Next) {
search = search->Next;
}
search->Next = m;
}
else {
CurrentModelFile->FirstMaterial = m;
}
m->Next = NULL;
}
MaterialPtr mwAddMaterial(char *name)
{
reg MaterialPtr new = NewMaterial();
new->Name = CopyOfString((name)? name: "Default");
AddMaterial(new);
return new;
}
static void RenameMaterial(MaterialPtr m, char *newname)
{
if (m->Name) {
Free(m->Name);
}
if (newname) {
m->Name = CopyOfString(newname);
}
else {
m->Name = NULL;
}
}
static TexturePtr NewTexture(void)
{
reg TexturePtr new = Allocate(sizeof(Texture));
new->Next = NULL;
new->pfdef = NULL;
new->MinFilter = MT_NULL;
new->MagFilter = MT_NULL;
new->ClampX = FALSE;
new->ClampY = FALSE;
new->Fast = FALSE;
new->Transparent = TRUE;
new->AlphaTest = 25;
return new;
}
static void FreeTexture(TexturePtr t)
{
if (t) {
if (t->File) {
Free(t->File);
}
Free(t);
}
}
static void AddTexture(reg TexturePtr t)
{
reg TexturePtr search;
if (search = CurrentModelFile->FirstTexture) {
while (search->Next) {
search = search->Next;
}
search->Next = t;
}
else {
CurrentModelFile->FirstTexture = t;
}
}
static void SearchForTextures(void)
{
char *path, *name, newpath[MaxFileName];
reg TexturePtr t = CurrentModelFile->FirstTexture;
while (t) {
if (ReadingExternal) { /* Exrefs search in a different way */
path = ExternalObject->File;
if ((path[0] IS '.') AND (path[1] IS '/')) {
sprintf(newpath, "%s/%s", FilePath, path+2);
}
else {
strcpy(newpath, path);
}
SplitFileName(newpath, &path, &name);
strcpy(newpath, path);
path = newpath;
}
else {
path = FilePath;
}
if (name = FindFile(t->File, IsAnImageFile, path, "textures")) {
Free(t->File);
t->File = CopyOfString(name);
}
t = t->Next;
}
}
TexturePtr mwAddTexture(char *filename)
{
TexturePtr new = NewTexture();
if (filename) {
new->File = CopyOfString(filename);
}
AddTexture(new);
return new;
}
/************************************************************************
Storage routines - polygons
************************************************************************/
PolygonBeadPtr NewPolygonBead(void)
{
reg PolygonBeadPtr new = Allocate(sizeof(PolygonBead));
new->Next = NULL;
new->Colour = DefaultColour;
new->Position[X] = new->Position[Y] = new->Position[Z] = 0.0;
new->TextureCoord[X] = new->TextureCoord[Y] = 0.0;
new->Normal[X] = new->Normal[Y] = new->Normal[Z] = 0.0;
new->Id = 0;
return new;
}
PolygonBeadPtr mwAddPolygonBead(PolygonBeadPtr *base, double *c, float *t)
{
reg PolygonBeadPtr pb, new = NewPolygonBead();
CopyXYZ(new->Position, c);
if (t) {
CopyXY(new->TextureCoord, t);
}
if (pb = *base) {
while (pb->Next) {
pb = pb->Next;
}
pb->Next = new;
}
else {
*base = new;
}
return new;
}
static PolygonBeadPtr AddPolygonBead(PolygonBeadPtr *base, real *c)
{
return mwAddPolygonBead(base, c, NULL);
}
PolygonBeadPtr CopyOfPolygonBead(reg PolygonBeadPtr pb)
{
reg PolygonBeadPtr new = Allocate(sizeof(PolygonBead));
new->Next = NULL;
new->Colour = pb->Colour;
CopyXYZ(new->Normal, pb->Normal);
CopyXYZ(new->Position, pb->Position);
CopyXY(new->TextureCoord, pb->TextureCoord);
return new;
}
static PolygonPtr NewPolygon(void)
{
reg PolygonPtr new = Allocate(sizeof(Polygon));
new->Next = NULL;
new->Child = NULL;
new->Smooth = TRUE;
new->Coloured = TRUE;
new->Texture = NULL;
new->Material = NULL;
new->FirstBead = NULL;
new->Envmapped = FALSE;
new->LightGroup = 0;
new->Normal[X] =
new->Normal[Y] =
new->Normal[Z] = 0.0;
new->Colour = DefaultColour;
return new;
}
static PolygonPtr PolygonCopier(reg PolygonPtr p)
{
reg PolygonPtr new = NewPolygon();
reg PolygonBeadPtr pb, newpb, lastpb;
new->Smooth = p->Smooth;
new->Coloured = p->Coloured;
new->Colour = p->Colour;
new->Texture = p->Texture;
new->Material = p->Material;
new->Envmapped = p->Envmapped;
new->LightGroup = p->LightGroup;
CopyXYZ(new->Normal, p->Normal);
lastpb = NULL;
LoopThroughPolygonsBeads(p, pb) {
newpb = CopyOfPolygonBead(pb);
if (lastpb) {
lastpb->Next = newpb;
}
else {
new->FirstBead = newpb;
}
lastpb = newpb;
}
return new;
}
static void CopyChildren(reg PolygonPtr parent, reg PolygonPtr child)
{
reg PolygonPtr new, lastc = NULL;
while (child) {
new = PolygonCopier(child);
if (lastc) {
lastc->Next = new;
}
else {
parent->Child = new;
}
lastc = new;
if (child->Child) {
CopyChildren(new, child->Child);
}
child = child->Next;
}
}
PolygonPtr CopyOfPolygon(reg PolygonPtr p)
{
reg PolygonPtr new = PolygonCopier(p);
if (p->Child) {
CopyChildren(new, p->Child);
}
return new;
}
static void LinkPolygon(PolygonPtr p, TreePtr t, PolygonPtr parent)
{
if (parent) {
p->Next = parent->Child;
parent->Child = p;
}
else if (t) {
p->Next = t->FirstPolygon;
t->FirstPolygon = p;
}
else {
fail("AddPolygon", "You must specify either a tree branch or a parent");
}
}
PolygonPtr AddPolygon(PolygonBeadPtr beads, TreePtr t, PolygonPtr parent)
{
reg PolygonBeadPtr b = beads;
reg PolygonPtr new = NewPolygon();
new->FirstBead = b;
while (b) {
b->Owner = new;
b = b->Next;
}
LinkPolygon(new, t, parent);
return new;
}
static void TrashPolygon(reg PolygonPtr p)
{
reg PolygonBeadPtr pb, nextpb;
pb = p->FirstBead;
while (pb) {
nextpb = pb->Next;
Free(pb);
pb = nextpb;
}
Free(p);
}
static void ChildFreer(reg PolygonPtr p)
{
reg PolygonPtr child, nextp;
while (p) {
nextp = p->Next;
if (child = p->Child) {
ChildFreer(child);
}
TrashPolygon(p);
p = nextp;
}
}
void FreePolygon(PolygonPtr p)
{
reg PolygonPtr child;
reg PolygonBeadPtr pb, nextpb;
if (child = p->Child) {
ChildFreer(child);
}
pb = p->FirstBead;
while (pb) {
nextpb = pb->Next;
Free(pb);
pb = nextpb;
}
Free(p);
}
/************************************************************************
Storage routines - tree branches
************************************************************************/
static void Identify(real (*mat)[4])
{
reg real zero = 0.0, one = 1.0;
mat[X][X] = one; mat[X][Y] = zero; mat[X][Z] = zero; mat[X][W] = zero;
mat[Y][X] = zero; mat[Y][Y] = one; mat[Y][Z] = zero; mat[Y][W] = zero;
mat[Z][X] = zero; mat[Z][Y] = zero; mat[Z][Z] = one; mat[Z][W] = zero;
mat[W][X] = zero; mat[W][Y] = zero; mat[W][Z] = zero; mat[W][W] = one;
}
TreePtr NewTreeBranch(int type, char *name)
{
TreePtr new = Allocate(sizeof(Tree));
bzero(new, sizeof(Tree));
if (name) {
reg int i, l;
char newname[MaxName];
strncpy(newname, name, MaxName);
name = newname;
l = strlen(name);
if (l > (MaxName-1)) {
l = MaxName-1;
}
for (i=0; i<l; i++) {
if ((name[i] < 32) OR (name[i] > 126)) {
name[i] = '.';
}
}
name[i] = '\0';
}
else {
switch (type) {
case GroupBranch: name = "Group"; break;
case PolygonBranch: name = "Poly"; break;
case LodBranch: name = "Lod"; break;
case InstanceBranch: name = "Object"; break;
case SwitchBranch: name = "Switch"; break;
case SwitchOutput: name = "Switch"; break;
case DcsBranch:
case DcsOutput: name = "DCS"; break;
case VRMLBranch: name = "VRML"; break;
case ActivatorEngine: name = "Activator"; break;
case DeactivatorEngine: name = "Deactivator"; break;
case TimeEngine: name = "Time"; break;
case LineEngine: name = "Line"; break;
case AngleEngine: name = "Angle"; break;
case WaveEngine: name = "Wave"; break;
case SensorEngine: name = "Sensor"; break;
case ScalarEngine: name = "Scalar"; break;
case SplineEngine: name = "Spline"; break;
case CompareEngine: name = "Compare"; break;
case MatrixEngine: name = "Matrix"; break;
default: fail("NewTreeBranch", "Unknown branch type");
}
}
new->Type = type;
new->Name = CopyOfString(name);
new->HasEye = TRUE;
new->EyeOpen = TRUE;
new->Visible = TRUE;
new->Backfaced = TRUE;
new->ShareNormals = TRUE;
new->SwitchOut = 10000;
new->IsInline = TRUE;
new->SeqTime = 0.0;
new->SeqType = mwSeqCycle;
Identify(new->Transformation);
Identify(new->DcsMatrix);
new->StartActive = TRUE;
new->NoWaves = 1.0;
new->WaveTime = 1.0;
new->Scale = 1.0;
return new;
}
static void RenameBranch(TreePtr t, char *newname)
{
if (t->Name) {
Free(t->Name);
}
if (newname) {
t->Name = CopyOfString(newname);
}
else {
t->Name = NULL;
}
}
void FreeTree(TreePtr t)
{
reg PolygonPtr p, nextp;
reg TreePtr recurse, next;
while (t) {
next = t->Down;
if (recurse = t->Across) {
FreeTree(recurse);
}
if (t->Type IS PolygonBranch) {
p = t->FirstPolygon;
while (p) {
nextp = p->Next;
FreePolygon(p);
p = nextp;
}
}
if (t->Name) {
Free(t->Name);
}
Free(t);
t = next;
}
}
static void TreeScanner(TreePtr t, void (*callback)(reg const TreePtr, reg const void*), void *vars)
{
while (t) {
callback(t, vars);
if (t->Across) {
TreeScanner(t->Across, callback, vars);
}
t = t->Down;
}
}
void ScanTree(reg TreePtr t, void (*callback)(reg const TreePtr, reg const void*), void *vars)
{
if (t) {
callback(t, vars);
TreeScanner(t->Across, callback, vars);
}
}
void mwAddTreeBranch(TreePtr parent, TreePtr newchild)
{
reg TreePtr t = parent;
if (t->Across) {
t = t->Across;
while (t->Down) {
t = t->Down;
}
t->Down = newchild;
}
else {
t->Across = newchild;
}
newchild->Down = NULL;
}
/************************************************************************
Storage routines - motion paths
************************************************************************/
PathPtr NewPath(void)
{
reg PathPtr p = Allocate(sizeof(Path));
p->FirstBead = NULL;
p->Closed = FALSE;
p->Smoothing = 2;
p->Basis = BSpline;
return p;
}
PathBeadPtr AddBeadToPathEnd(reg PathPtr p, reg CoordinatePtr c)
{
reg PathBeadPtr b = p->FirstBead, new = Allocate(sizeof(PathBead));
new->Rounded = TRUE;
if (b) {
while (b->Next) {
b = b->Next;
}
b->Next = new;
}
else {
p->FirstBead = new;
}
return new;
}
/************************************************************************
Storage routines - objects
************************************************************************/
ModelObjectPtr AddObject(char *name)
{
reg ModelObjectPtr search, new = Allocate(sizeof(ModelObject));
if (search = CurrentModelFile->FirstObject) {
while (search->Next) {
search = search->Next;
}
search->Next = new;
}
else {
CurrentModelFile->FirstObject = new;
}
new->Next = NULL;
if (!name) {
name = "Unnamed";
}
new->Name = CopyOfString(name);
new->Tree = NULL;
new->Engines = NULL;
new->IsTopLevel = FALSE;
new->FirstConstructionVertex = NULL;
new->File = NULL;
new->External = NULL;
return new;
}
static void FreeObject(reg ModelObjectPtr o)
{
if (o->External) {
o->Tree = NULL;
FreeExternalFile(o->External);
}
FreeTree(o->Tree);
if (o->Name) {
Free(o->Name);
}
Free(o);
}
/************************************************************************
Initialisation/finalisation of file read...
************************************************************************/
static FILE *GetReadyForRead(char *name)
{
FILE *f;
if (f = fopen(name, "rb")) {
FileError = FALSE;
NewModelFile();
mwOriginalPath[0] = '\0';
}
else {
SetError(FILE_NOT_FOUND);
}
return f;
}
static void FinishReading(FILE *f, float compatibility)
{
if (f) {
fclose(f);
}
}
/************************************************************************
Free the storage used by a model file
************************************************************************/
static void FreeExternalFile(reg ModelFilePtr f)
{
reg TexturePtr t, nextt;
reg MaterialPtr m, nextm;
reg ModelObjectPtr o, nexto;
o = f->FirstObject;
while (o) {
nexto = o->Next;
FreeObject(o);
o = nexto;
}
t = f->FirstTexture;
while (t) {
nextt = t->Next;
FreeTexture(t);
t = nextt;
}
m = f->FirstMaterial;
while (m) {
nextm = m->Next;
FreeMaterial(m);
m = nextm;
}
Free(f);
}
void mwFreeFile(ModelFilePtr f)
{
reg TexturePtr t, nextt;
reg MaterialPtr m, nextm;
reg ModelObjectPtr o, nexto;
o = f->FirstObject;
while (o) {
nexto = o->Next;
FreeObject(o);
o = nexto;
}
t = f->FirstTexture;
while (t) {
nextt = t->Next;
FreeTexture(t);
t = nextt;
}
m = f->FirstMaterial;
while (m) {
nextm = m->Next;
FreeMaterial(m);
m = nextm;
}
Free(f);
}
/************************************************************************
Convert between coordinate systems
************************************************************************/
static int ConvertDirection;
enum { To_Y_is_up, To_Z_is_up };
#define ConvertXYZ(c, temp) \
if (ConvertDirection IS To_Y_is_up) { \
temp = c[Y]; \
c[Y] = c[Z]; \
c[Z] = -temp; \
} \
else { \
temp = c[Y]; \
c[Y] = -c[Z]; \
c[Z] = temp; \
}
#define ConvertPoly \
LoopThroughPolygonsBeads(p, pb) { \
ConvertXYZ(pb->Position, dtemp); \
} \
ConvertXYZ(p->Normal, temp); \
if (p->Smooth AND !p->Coloured) { \
LoopThroughPolygonsBeads(p, pb) { \
ConvertXYZ(pb->Normal, temp); \
} \
}
static void ConvertChildren(reg PolygonPtr p)
{
reg float temp;
reg double dtemp;
reg PolygonBeadPtr pb;
while (p) {
ConvertPoly;
if (p->Child) {
ConvertChildren(p->Child);
}
p = p->Next;
}
}
static void ConvertTree(reg TreePtr t)
{
reg int i;
reg float temp;
reg double dtemp;
reg PolygonPtr p;
reg PolygonBeadPtr pb;
while (t) {
if (t->Across) {
ConvertTree(t->Across);
}
if (t->Type IS PolygonBranch) {
LoopThroughBranchesPolygons(t, p) {
ConvertPoly;
if (p->Child) {
ConvertChildren(p->Child);
}
}
}
else if (t->Type IS InstanceBranch) {
for (i=0; i<4; i++) {
if (ConvertDirection IS To_Y_is_up) {
dtemp = t->Transformation[Y][i];
t->Transformation[Y][i] = t->Transformation[Z][i];
t->Transformation[Z][i] = -dtemp;
}
else {
dtemp = t->Transformation[Y][i];
t->Transformation[Y][i] = -t->Transformation[Z][i];
t->Transformation[Z][i] = dtemp;
}
}
for (i=0; i<4; i++) {
if (ConvertDirection IS To_Y_is_up) {
dtemp = t->Transformation[i][Y];
t->Transformation[i][Y] = t->Transformation[i][Z];
t->Transformation[i][Z] = -dtemp;
}
else {
dtemp = t->Transformation[i][Y];
t->Transformation[i][Y] = t->Transformation[i][Z];
t->Transformation[i][Z] = -dtemp;
}
}
}
t = t->Down;
}
}
static void DoCoordinateConversion(void)
{
reg ModelObjectPtr o = CurrentModelFile->FirstObject;
while (o) {
ConvertTree(o->Tree);
o = o->Next;
}
}
void mwConvertTo_Y_is_up(void)
{
ConvertDirection = To_Y_is_up;
DoCoordinateConversion();
}
void mwConvertTo_Z_is_up(void)
{
ConvertDirection = To_Z_is_up;
DoCoordinateConversion();
}
/************************************************************************
Read an external file...
************************************************************************/
static ModelFilePtr LoadExternalFile(reg char *name)
{
reg flag WasExternal;
reg ModelFilePtr f, c;
c = CurrentModelFile;
WasExternal = ReadingExternal;
ReadingExternal = TRUE;
ReadModel(name);
f = CurrentModelFile;
if (FileError) {
FreeExternalFile(f);
f = NULL;
}
CurrentModelFile = c;
ReadingExternal = WasExternal;
return f;
}